/******************************************************************************\
 * Filename   : enc_fifo.c
 * Copyright  : 
 * Created    : 2018-11-09 by litao
 * Description:
 * 
\******************************************************************************/

#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
#include <string.h>
#include "enc_fifo.h"

carrier_buffer_t *alloc_carrier_buffer(size_t i_size)
{
    carrier_buffer_t *buffer = (carrier_buffer_t *)malloc(sizeof(carrier_buffer_t) + i_size);
    if (buffer == NULL) {
        return NULL;
    }

	memset(buffer, 0, sizeof(carrier_buffer_t) + i_size);
    uclist_init(&buffer->node);
	buffer->private_flag = 0;
	buffer->data_offset = 0;
	buffer->data_len = 0;
	buffer->data_max = i_size;
	
    return buffer;
}

/* */
carrier_buffer_t *alloc_cccarrier_buffer(size_t i_size)
{
    carrier_buffer_t *buffer = (carrier_buffer_t *)malloc(sizeof(carrier_buffer_t) + i_size);
    if (buffer == NULL) {
        return NULL;
    }

	memset(buffer, 0, sizeof(carrier_buffer_t) + i_size);
    uclist_init(&buffer->node);
	buffer->private_flag = 0;
	buffer->data_offset = 0;
	buffer->data_len = 0;
	buffer->data_max = i_size;
	
    return buffer;
}

void free_carrier_buffer(carrier_buffer_t **buffer)
{
	if (*buffer != NULL) {
    	free(*buffer);
		*buffer = NULL;
	}
}

carrier_buffer_t *copy_carrier_buffer(carrier_buffer_t *p_src_carrier)
{
	carrier_buffer_t *p_buffer;

	p_buffer = alloc_cccarrier_buffer(p_src_carrier->data_len);
    if (p_buffer == NULL) {
        return NULL;
    }	

	memcpy(p_buffer, p_src_carrier, sizeof(carrier_buffer_t) + p_src_carrier->data_len);

	return p_buffer;
}

carrier_buffer_t *qlist_pop(qlist_body *fifo, int block_flag)
{
    ucnode_s *p_node = NULL;
	carrier_buffer_t *p_buffer = NULL;

	do {
		uclock_lock(&fifo->lock);    
	    p_node = uclist_get_first(&fifo->list);
	    if(p_node != NULL)
	    {
	        p_buffer = uclist_entry(p_node, carrier_buffer_t, node);
	        uclist_del(p_node);
	        if(fifo->node_count > 0) {
	            fifo->node_count--;
	        }
			uclock_unlock(&fifo->lock); 
			break;
	    } else {
	    	if (block_flag) {
				fifo->wait_sig = 1;
				block_flag = 0;
	    	} else {
				uclock_unlock(&fifo->lock); 
				break;
			}
		}
		uclock_unlock(&fifo->lock); 

		if (fifo->wait_sig) {
			ucsig_wait(&fifo->signal);
			fifo->wait_sig = 0;
		}
	} while(1);

    return p_buffer;
}


int qlist_push(qlist_body *fifo, carrier_buffer_t *buffer)
{
	uclock_lock(&fifo->lock);
    uclist_add_tail(&buffer->node, &fifo->list);
    fifo->node_count++;
	if(fifo->wait_sig) {
	    ucsig_lock(&fifo->signal);   
	    ucsig_signal(&fifo->signal);
	    ucsig_unlock(&fifo->signal);            
	}  	
	uclock_unlock(&fifo->lock);   

    return 0;
}

void qlist_destroy(qlist_body *fifo)
{
    ucnode_s *p_node;
    ucnode_s *p_node_temp;
    carrier_buffer_t *p_buf;
    
	uclock_lock(&fifo->lock);
    uclist_for_each_safe(p_node,p_node_temp,&fifo->list)
    {
        p_buf = uclist_entry(p_node, carrier_buffer_t, node);
        uclist_del(p_node);
        free_carrier_buffer(&p_buf);
		fifo->node_count--;
    }       
	uclock_unlock(&fifo->lock);    
}

int qlist_count(qlist_body *fifo)
{
    uclock_lock(&fifo->lock);
    int count = fifo->node_count;
    uclock_unlock(&fifo->lock);
    return count;
}

int qlist_safe_push(qlist_body *fifo, carrier_buffer_t *buffer)
{
	int unit_num = 0;

	unit_num = qlist_count(fifo);
	if (unit_num > QUEUE_MAX_UNIT_NUM) {
		qlist_destroy(fifo);
		uc_err("queue reach max clean it\n");
	}

	qlist_push(fifo, buffer);

	return 0;
}

int initial_qlist_body(qlist_body *p_list)
{
    p_list->node_count = 0;
    p_list->wait_sig = 0;
    ucsig_init(&p_list->signal);
	uclock_init(&p_list->lock);
	uclist_init(&p_list->list);  
   
    return 0;
}

int uninitial_qlist_body(qlist_body *p_list)
{
    qlist_destroy(p_list);
    ucsig_destroy(&p_list->signal);
    uclock_destroy(&p_list->lock);

    return 0;
}

int initial_cycle_queue(cycle_queue *p_fifo)
{
    qlist_body *p_list;

    p_list = &p_fifo->empty_fifo;
    p_list->node_count = 0;
    p_list->wait_sig = 0;
    ucsig_init(&p_list->signal);
	uclock_init(&p_list->lock);
	uclist_init(&p_list->list);  

    p_list = &p_fifo->used_fifo;
    p_list->node_count = 0;
    p_list->wait_sig = 0;
    ucsig_init(&p_list->signal);
	uclock_init(&p_list->lock);
	uclist_init(&p_list->list);     
    return 0;
}

int uninitial_cycle_queue(cycle_queue *p_fifo)
{
    qlist_body *p_list;

    p_list = &p_fifo->empty_fifo;
    qlist_destroy(p_list);
    ucsig_destroy(&p_list->signal);
    uclock_destroy(&p_list->lock);

    p_list = &p_fifo->used_fifo;
    qlist_destroy(p_list);
    ucsig_destroy(&p_list->signal);
    uclock_destroy(&p_list->lock);

    return 0;
}


